package streamproc;

import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Vector;
import event.Event;
import event.EventFormatManager;
import event.DEFINES;
import event.DEFINES.CEPLEventDataFieldValue;
import event.DEFINES.CEPLEventDataFieldType;
import event.UnknownDataFieldException;
import streamdef.StreamCondition;
import streamdef.StreamDefinitionManager;
import streamdef.EventSet;

// Component that creates a complex event out of a valid set of Events
public class TransformerComponent extends ChainComponent {
	private static TransformerComponent sInstance = null;

	public static TransformerComponent instance() {
		if (sInstance == null)
			sInstance = new TransformerComponent();

		return sInstance;
	}

	private static int bufferSize = 192;

	private TransformerComponent() {
	}

	public void reset() {
	}

	protected void finalize() {
		reset();
	}

	public void init() {
		reset();
	}

	public synchronized void processQueryResults(Vector<EventSet> qrVector) {
		Vector<Event> result = new Vector<Event>();

		EventSet qr = null;
		for (int g = 0; g < qrVector.size(); ++g) {
			qr = qrVector.get(g);
			Event e = getEventByByteArray(qr);
			// Event e = getEventByHashMap(qr);
			if (e != null)
				result.add(e);
		}

		qrVector.clear();
		next.processEvents(result);
	}

	private Event getEventByByteArray(EventSet qr) {
		EventFormatManager efm = EventFormatManager.instance();
		long streamID = qr.getStreamID();
		StreamCondition streamCondition = StreamDefinitionManager.instance()
				.getParsedQuery(streamID);
		Vector<DEFINES.CEPLEventDataFieldDefinition> resultEventFormat = efm
				.getEventFormat(streamID);

		if (streamCondition == null)
			return null;
		if (resultEventFormat == null)
			return null;

		try {
			ByteBuffer buf = ByteBuffer.allocate(bufferSize);

			for (int i = 0; i < resultEventFormat.size(); ++i) {
				String fieldName = resultEventFormat.get(i).fieldName;
				CEPLEventDataFieldType type = efm.getFieldValueType(streamID,
						resultEventFormat.get(i).fieldName);

				long internalID = streamCondition
						.getOrigInternalStreamID(fieldName);
				long externalID = streamCondition
						.getExternalStreamID(internalID);
				String externalFieldName = streamCondition
						.getOrigFieldName(fieldName);
				Event e = qr.getEventForInternalStreamID(internalID);

				if (type == CEPLEventDataFieldType.CHAR)
					buf.putChar(e.getCharacter(externalFieldName));
				else if (type == CEPLEventDataFieldType.DOUBLE)
					buf.putDouble(e.getDouble(externalFieldName));
				else if (type == CEPLEventDataFieldType.FLOAT)
					buf.putFloat(e.getFloat(externalFieldName));
				else if (type == CEPLEventDataFieldType.INT)
					buf.putInt(e.getInteger(externalFieldName));
				else if (type == CEPLEventDataFieldType.LONG)
					buf.putLong(e.getLong(externalFieldName));
				else if (type == CEPLEventDataFieldType.SHORT)
					buf.putShort(e.getShort(externalFieldName));
				else if (type == CEPLEventDataFieldType.TEXT) {
					short lengthInBytes = EventFormatManager.instance()
							.getLengthInBytes(externalID, externalFieldName);
					String text = e.getString(externalFieldName);
					if (lengthInBytes == 0)// preceding length required
						buf.putShort((short) (text.length()));
					buf.put(text.getBytes());
				}
			}

			ByteBuffer buf2 = ByteBuffer.allocate(bufferSize - buf.remaining());
			buf2.put(buf.array(), 0, buf2.capacity());
			byte[] data = buf2.array();
			Event e = new Event(streamID, false, false, true, data);

			return e;
		} catch (UnknownDataFieldException exp) {
			exp.printStackTrace();
			return null;
		}
	}

	@SuppressWarnings("unused")
	private Event getEventByHashMap(EventSet qr) {
		EventFormatManager efm = EventFormatManager.instance();
		long streamID = qr.getStreamID();
		StreamCondition streamCondition = StreamDefinitionManager.instance()
				.getParsedQuery(streamID);
		Vector<DEFINES.CEPLEventDataFieldDefinition> resultEventFormat = efm
				.getEventFormat(streamID);
		HashMap<String, CEPLEventDataFieldValue> hashMap = new HashMap<String, CEPLEventDataFieldValue>();

		if (streamCondition == null)
			return null;
		if (resultEventFormat == null)
			return null;

		for (int i = 0; i < resultEventFormat.size(); ++i) {
			String fieldName = new String(resultEventFormat.get(i).fieldName);
			CEPLEventDataFieldType type = efm.getFieldValueType(streamID,
					resultEventFormat.get(i).fieldName);
			short lengthInBytes = efm.getLengthInBytes(streamID, fieldName);

			CEPLEventDataFieldValue value = new CEPLEventDataFieldValue();
			value.fieldName = fieldName;
			value.type = type;
			value.lengthInBytes = lengthInBytes;

			long internalID = streamCondition
					.getOrigInternalStreamID(fieldName);
			long externalID = streamCondition.getExternalStreamID(internalID);
			String externalFieldName = streamCondition
					.getOrigFieldName(fieldName);
			Event e = qr.getEventForInternalStreamID(internalID);

			try {
				if (type == CEPLEventDataFieldType.CHAR)
					value.value = new Character(
							e.getCharacter(externalFieldName));
				else if (type == CEPLEventDataFieldType.DOUBLE)
					value.value = new Double(e.getDouble(externalFieldName));
				else if (type == CEPLEventDataFieldType.FLOAT)
					value.value = new Float(e.getFloat(externalFieldName));
				else if (type == CEPLEventDataFieldType.INT)
					value.value = new Integer(e.getInteger(externalFieldName));
				else if (type == CEPLEventDataFieldType.LONG)
					value.value = new Long(e.getLong(externalFieldName));
				else if (type == CEPLEventDataFieldType.SHORT)
					value.value = new Short(e.getShort(externalFieldName));
				else if (type == CEPLEventDataFieldType.TEXT) {
					short lengthInBytes2 = EventFormatManager.instance()
							.getLengthInBytes(externalID, externalFieldName);
					String text = e.getString(externalFieldName);
					if (lengthInBytes2 == 0)// preceding length required
						value.lengthInBytes = (short) text.length();

					value.value = text;
				}

				hashMap.put(fieldName, value);
			} catch (UnknownDataFieldException exp) {
				exp.printStackTrace();
				return null;
			}
		}

		return new Event(streamID, false, false, true, hashMap);
	}
}
